package org.example.mall.Controller;

import jakarta.validation.constraints.Pattern;
import org.example.mall.utils.JwtUtil;
import org.example.mall.utils.Md5Util;
import org.example.mall.utils.ThreadLocalUtil;
import org.hibernate.validator.constraints.URL;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.example.mall.Pojo.Users;

import lombok.extern.slf4j.Slf4j;
import org.example.mall.Pojo.Result;
import org.example.mall.Service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


//用户模块相关的前端接口,面向前端接口
//无论是get还是post请求都是用相同的写法，post请求适用于修改和写入数据，get请求适用于读取数据，登录这种对安全性有要求的我们采用post
@Slf4j//相当于private static Logger log= LoggerFactory.getLogger(StudentController.class);//导入日志记录对象
@Controller//控制层
@RestController//请求处理类，综合了@ResponseBody和@Controller的功能，每个方法的返回值都会以 JSON 或 XML 的形式直接写入 HTTP 响应体中
@RequestMapping("/User")
@Validated
public class UsersController {

    @Autowired
    private UsersService userService;
    @Autowired
    //用于操控redis中的字符串对象
    private StringRedisTemplate stringRedisTemplate;

    //用户注册接口
    @RequestMapping(value="/Register",method = RequestMethod.POST)
    public Result Register(@Pattern(regexp = "^\\S{5,16}$")String Username,
                           @Pattern(regexp = "^\\S{5,16}$")String Password){
        //用户名是否已被占用
        log.info("名称占用检查："+Username);
        Users u = userService.findByUsername(Username);
        if (u == null) {
            //用户名没有占用
            //注册
            log.info("注册："+Username);
            userService.register(Username, Password);
            return Result.success();
        } else {
            //占用
            return Result.error("用户名已被占用");
        }
    }

    //用户登录接口
    @RequestMapping(value="/Login",method = RequestMethod.POST)//method可以指定请求类型,也可以用@Postmapping代替
    public Result<String> Login(@Pattern(regexp = "^\\S{5,16}$")String Username,
                        @Pattern(regexp = "^\\S{5,16}$")String Password){
        //根据用户名查询User
        log.info("根据用户名查询User："+Username);
        Users u = userService.findByUsername(Username);
        //判断是否查询到
        if (u != null) {
            //判断密码是否正确,密码是密文
            log.info("密码校验："+u.getPassword());
            if(Md5Util.getMD5String(Password).equals(u.getPassword())){
                Map<String,Object> claims = new HashMap<String,Object>();
                //再次注意，载荷不应该放入敏感信息
                claims.put("id",u.getId());
                claims.put("username",Username);
                String token = JwtUtil.genToken(claims);

                //将token存储到redis中
                //opsForValue()用于操控字符串类型的键值对
                ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
                //设置过期以防token越存越多，过期时间与登录过期时间保持一致
                operations.set(token,token,12, TimeUnit.HOURS);

                return Result.success(token);
            }else{
                return Result.error("密码错误");
            }
        }else{
            //不存在该用户
            return Result.error("用户名不存在");
        }
    }

    //获取用户详细信息接口
    @RequestMapping(value = "/UserInfo",method = RequestMethod.GET)
    public Result<Users> UserInfo(/*@RequestHeader(name = "Authorization") String token*/){
        //根据令牌获取用户名
//        Map<String, Object> map = JwtUtil.parseToken(token);
//        String username = map.get("username").toString();
        //根据ThreadLocal存储map获取用户名
        Map<String, Object> map = ThreadLocalUtil.get();
        String username = map.get("username").toString();
        //根据用户名查询用户
        Users u = userService.findByUsername(username);
        return Result.success(u);
    }

    //更新用户基本信息接口
    @RequestMapping(value = "/Update",method = RequestMethod.PUT)
    //@RequestBody将前端传来的json字符串对象转换为实体类
    //@Validated使实体类Validated注解生效
    public Result<Users> Update(@RequestBody @Validated Users newUser){
//        log.info("封装好的实体类User："+user.toString());
        //根据令牌获取用户
        Map<String, Object> map = ThreadLocalUtil.get();
        String username = map.get("username").toString();
        Users oldUser = userService.findByUsername(username);
        //根据前端传入信息更新用户
        oldUser.setNickname(newUser.getNickname());
        oldUser.setEmail(newUser.getEmail());
        userService.update(oldUser);
        return Result.success();
    }

    //更新用户头像
    @RequestMapping(value = "/UpdateAvatar",method = RequestMethod.PATCH)
    //@RequestParam用于接收Query参数，默认接收的是Body的urlencoded参数
    //@URL校验参数是否为URL地址
    public Result UpdateAvatar(@RequestParam @URL String avatarUrl){
        //根据令牌获取用户
        Map<String, Object> map = ThreadLocalUtil.get();
        Integer Id = (Integer) map.get("id");
        userService.UpdateAvatar(avatarUrl,Id);
        return Result.success();
    }

    //更新用户密码
    @RequestMapping(value = "/UpdatePwd",method = RequestMethod.PATCH)
    public Result UpdatePwd(@RequestBody Map<String,String> params, @RequestHeader(name = "Authorization") String token){
        //根据令牌获取用户
        Map<String, Object> map = ThreadLocalUtil.get();
        String username = map.get("username").toString();
        Integer Id = (Integer) map.get("id");
        Users u = userService.findByUsername(username);

        //没有合适的可用注解，手动校验参数
        String old_pwd = params.get("old_pwd");
        String new_pwd = params.get("new_pwd");
        String re_pwd = params.get("re_pwd");

        //密码格式校验
        String regex = "^\\S{5,16}$";
        boolean match1 = old_pwd.matches(regex);
        boolean match2 = new_pwd.matches(regex);
        boolean match3 = re_pwd.matches(regex);
        if(!match1||!match2||!match3){
            return Result.error("密码格式错误");
        }

        //调用Service拿到原密码，校验与old_pwd是否相同
        log.info("原密码校验："+u.getPassword());
        if(!Md5Util.getMD5String(old_pwd).equals(u.getPassword())){
            return Result.error("原密码错误");
        }

        //校验re_pwd与new_pwd是否一致
        if(!new_pwd.equals(re_pwd)){
            return Result.error("确认新密码错误");
        }

        //调用Service完成密码更新
        userService.UpdatePwd(new_pwd,Id);

        //删除旧token
        ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
        operations.getOperations().delete(token);

        return Result.success();
    }
}
